home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 May: Tool Chest / Dev.CD May 97 TC.toast / Sample Code / Processes / ProcDoggie 2.1b1 / UMenuHandler.p < prev    next >
Encoding:
Text File  |  1997-03-20  |  14.8 KB  |  455 lines  |  [TEXT/CWIE]

  1. UNIT UMenuHandler;
  2.  
  3. {-------------------------------------------------------------------------------
  4.     File:        UMenuHandler.p
  5.  
  6.     Contains:    Menu-handling routines.
  7.  
  8.     Written by:    Forrest Tanaka
  9.  
  10.     Copyright:    © 1988-1997 by Apple Computer, Inc., all rights reserved.
  11.  
  12.     Change History (most recent first):
  13.  
  14.     You may incorporate this sample code into your applications without
  15.     restriction, though the sample code has been provided "AS IS" and the
  16.     responsibility for its operation is 100% yours.  However, what you are
  17.     not permitted to do is to redistribute the source as "DSC Sample Code"
  18.     after having made changes. If you're going to re-distribute the source,
  19.     we require that you make it clear in the source that the code was
  20.     descended from Apple Sample Code, but that you've made changes.
  21. --------------------------------------------------------------------------------
  22. #
  23. #    All of the code in this module is used to maintain the menus and to handle
  24. #    menu selections by the user.
  25. #
  26. -------------------------------------------------------------------------------}
  27. {[j=20/57/1$] Pasmat Options}
  28.  
  29.  
  30. INTERFACE
  31.  
  32.  
  33. (*******************************************************************************
  34. * Used Units
  35. *******************************************************************************)
  36.  
  37.     USES
  38.         (* Application *)
  39.         UGlobals
  40.         ,UProcessUtils
  41.         ,UProcessGuts
  42.         ;
  43.  
  44.  
  45. (*******************************************************************************
  46. * Constants
  47. *******************************************************************************)
  48.  
  49.     CONST
  50.         mApple = 128; {Menu ID and resource ID of Apple menu}
  51.         iAbout = 1;   {Menu item number of About SevenPaint item}
  52.  
  53.         mFile        = 129; {Menu ID and resource ID of File menu}
  54.         iClose         = 1;    {Menu item number of Close item}
  55.         iLaunchFore  = 3;   {Menu item number of Launch to Foreground… item}
  56.         iLaunchBack  = 4;   {Menu item number of Launch to Background… item}
  57.         iLaunchTo    = 5;   {Menu item number of Launch To… item}
  58.         iJustLaunch  = 7;   {Menu item number of Simple Launch item}
  59.         iOpenLaunch  = 8;   {Menu item number of Open Documents on Launch item}
  60.         iPrintLaunch = 9;   {Menu item number of Print Documents on Launch item}
  61.         iQuit        = 11;  {Menu item number of Quit item}
  62.  
  63.         mProcess          = 130; {Menu ID and resource ID of Process menu}
  64.         iBringFront       = 1;   {Menu item number of Bring Process to Front item}
  65.         iShowProcessInfo  = 2;   {Menu item number of Show Process Info item}
  66.         iTerminateProcess = 3;   {Menu item number of Terminate Process item}
  67.  
  68.  
  69. (*******************************************************************************
  70. * StartMenus - Do additional initialization of the menus
  71. *
  72. * This routine is called just after calling the Utilities sample code routine,
  73. * StandardMenuSetup.  This application needs to do just a little bit of
  74. * additional initialization for menus.  See below for details.
  75. *
  76. * If there isn’t enough memory to load the menus, then the gError global is set
  77. * to memFullErr.  If desired menu resources couldn’t be found, then gError is
  78. * set to resNotFound.  If any other error occurs, then gError is set to
  79. * dsSysErr.
  80. *******************************************************************************)
  81.  
  82.     PROCEDURE StartMenus;
  83.  
  84.  
  85. (*******************************************************************************
  86. * DoMenuChoice - Dispatch to the appropriate routine for a menu choice
  87. *
  88. * When it’s determined that a menu item was chosen, this routine is called to
  89. * dispatch to the appropriate routine for the chosen menu item.  The menu item
  90. * and menu number returned by MenuSelect and MenuKey is passed in the menuChoice
  91. * parameter.
  92. *******************************************************************************)
  93.  
  94.     PROCEDURE DoMenuChoice (menuChoice: LongInt);
  95.  
  96.  
  97. (*******************************************************************************
  98. * FixMenus - Fix menus so that proper items are enabled and marked
  99. *
  100. * FixMenus is called to assure that menu items are disable, enabled, marked, and
  101. * unmarked appropriately.  It’s called at the end of every iteration of the main
  102. * event loop.
  103. *******************************************************************************)
  104.  
  105.     PROCEDURE FixMenus;
  106.  
  107.  
  108. IMPLEMENTATION
  109.  
  110.     USES
  111.         Resources
  112.         ,Devices
  113.         ,ToolUtils
  114.         ;
  115.         
  116. (*******************************************************************************
  117. * Constants
  118. *******************************************************************************)
  119.  
  120.     CONST
  121.         rMenuBar = 128; {Resource ID of this application’s MBAR resource}
  122.  
  123.         mFirst = mFile;    {Menu ID of the first non-Apple menu in the menu list}
  124.         mLast  = mProcess; {Menu ID of the last menu in the menu list}
  125.  
  126.  
  127. (*******************************************************************************
  128. * Types
  129. *******************************************************************************)
  130.  
  131.     TYPE
  132.         MenuGuide = RECORD
  133.             theMenu: MenuHandle; {Handle to this guide’s menu}
  134.             enables: LongInt     {Current enable flags}
  135.         END;
  136.  
  137.  
  138. (*******************************************************************************
  139. * Variables
  140. *******************************************************************************)
  141.  
  142.     VAR
  143.         gMenuGuides: ARRAY [mFirst..mLast] OF MenuGuide;
  144.  
  145. {$S Startup}
  146. (*******************************************************************************
  147. * Public: StartMenus
  148. *
  149. * The menu guide array is initialized with the menu handles and enable flags of
  150. * all menus.
  151. *
  152. * If GetNewMBar couldn’t load the MBAR resource, then it returns NIL and the
  153. * error code is in ResError, and I can deal with the error elegantly.  But, if
  154. * the GetNewMBar couldn’t load the menus themselves, then it’ll probably crash.
  155. *******************************************************************************)
  156.  
  157.     PROCEDURE StartMenus;
  158.  
  159.         VAR
  160.             menuBar:   Handle;  {Handle to the menu bar from the MBAR resource}
  161.             menuIndex: Integer; {Index into menu guide records}
  162.  
  163.     BEGIN
  164.         (* Load in the menu bar *)
  165.         menuBar := GetNewMBar (rMenuBar);
  166.         IF menuBar <> NIL THEN
  167.             BEGIN
  168.                 (* Set it, then dispose of it because SetMenuBar makes a copy *)
  169.                 SetMenuBar (menuBar);
  170.                 DisposeHandle (menuBar);
  171.  
  172.                 (* Add the desk accessories to the Apple menu *)
  173.                 AppendResMenu (GetMenuHandle (mApple), 'DRVR');
  174.  
  175.                 (* Initialize the menu guide array *)
  176.                 FOR menuIndex := mFile TO mProcess DO
  177.                     BEGIN
  178.                         gMenuGuides [menuIndex].theMenu := GetMenuHandle (menuIndex);
  179.                         gMenuGuides [menuIndex].enables := gMenuGuides [menuIndex].
  180.                                 theMenu^^.enableFlags
  181.                     END;
  182.  
  183.                 (* Draw the menu bar *)
  184.                 DrawMenuBar
  185.             END
  186.         ELSE
  187.             IF ResError = memFullErr THEN
  188.                 gError := memFullErr
  189.             ELSE IF (ResError = noErr) OR (ResError = resNotFound) THEN
  190.                 gError := resNotFound
  191.             ELSE
  192.                 gError := dsSysErr
  193.     END;
  194.  
  195.  
  196. {$S Main}
  197. (*******************************************************************************
  198. * Private: DoAppleMenu - Handle an Apple menu item choice
  199. *
  200. * This routine is called whenever it’s determined that the chosen menu item was
  201. * in the Apple menu.  If the chosen menu item that’s passed in the menuItem
  202. * parameter wasn’t the About item, the name of the menu item is retrieved and
  203. * then OpenDeskAcc is called with this name so that the desk accessory by that
  204. * name is opened.  The Process Manager can launch desk accessories, but
  205. * OpenDeskAcc should still be used if the user chooses any item in the Apple
  206. * menu.
  207. *******************************************************************************)
  208.  
  209.     PROCEDURE DoAppleMenu (menuItem: Integer);
  210.  
  211.         VAR
  212.             daName: Str255;  {Name of the chosen DA}
  213.             refNum: Integer; {Reference number of the DA, ignored}
  214.  
  215.     BEGIN
  216.         IF menuItem = iAbout THEN
  217.             ShowAboutBox
  218.         ELSE
  219.             BEGIN
  220.                 GetMenuItemText (GetMenuHandle (mApple), menuItem, (*<*)daName);
  221.                 refNum := OpenDeskAcc (daName)
  222.             END
  223.     END;
  224.  
  225.  
  226. {$S Main}
  227. (*******************************************************************************
  228. * Private: DoFileMenu - Handle a File menu item choice
  229. *
  230. * This routine is called whenever it’s determined that the chosen menu item was
  231. * in the File menu.  The item number of the chosen menu item is passed in the
  232. * menuItem parameter.
  233. *******************************************************************************)
  234.  
  235.     PROCEDURE DoFileMenu (menuItem: Integer);
  236.  
  237.         VAR
  238.             junkError: OSErr;
  239.             
  240.     BEGIN
  241.         CASE menuItem OF
  242.             iClose:
  243.                 DoWindowClose(FrontWindow);
  244.             iLaunchFore:
  245.                 DoLaunchInFront;
  246.             iLaunchBack:
  247.                 DoLaunchInBack;
  248.             iLaunchTo:
  249.                 DoLaunchTo;
  250.             iJustLaunch,
  251.             iOpenLaunch,
  252.             iPrintLaunch:
  253.                 DoLaunchMode (menuItem);
  254.             iQuit:
  255.                 junkError := DoQuit
  256.         END
  257.     END;
  258.  
  259.  
  260. {$S Main}
  261. (*******************************************************************************
  262. * Private: DoProcessMenu - Handle a Process menu item choice
  263. *
  264. * This routine is called whenever it’s determined that the chosen menu item was
  265. * in the Process menu.  The item number of the chosen menu item is passed in the
  266. * menuItem parameter.
  267. *******************************************************************************)
  268.  
  269.     PROCEDURE DoProcessMenu (menuItem: Integer);
  270.  
  271.     BEGIN
  272.         CASE menuItem OF
  273.             iBringFront:
  274.                 DoBringProcessToFront (FrontWindow);
  275.             iShowProcessInfo:
  276.                 DoGetProcessInfo (FrontWindow);
  277.             iTerminateProcess:
  278.                 DoTerminateProcess (FrontWindow)
  279.         END
  280.     END;
  281.  
  282.  
  283. {$S Main}
  284. (*******************************************************************************
  285. * Public: DoMenuChoice
  286. *
  287. * This routine should be self-explanatory.
  288. *******************************************************************************)
  289.  
  290.     PROCEDURE DoMenuChoice (menuChoice: LongInt);
  291.  
  292.         VAR
  293.             menuNum:     Integer; {Menu number of chosen menu}
  294.             menuItem:    Integer; {Item number of chosen menu item}
  295.             startTicks: longint; {TickCount when menu command started}
  296.     BEGIN
  297.         IF menuChoice <> 0 THEN
  298.             BEGIN
  299.                 startTicks := TickCount;
  300.                 
  301.                 (* Get the chosen menu item and menu number *)
  302.                 menuNum := HiWord (menuChoice);
  303.                 menuItem := LoWord (menuChoice);
  304.  
  305.                 (* Dispatch the appropriate menu-handling routine *)
  306.                 CASE menuNum OF
  307.                     mApple:
  308.                         DoAppleMenu (menuItem);
  309.                     mFile:
  310.                         DoFileMenu (menuItem);
  311.                     mProcess:
  312.                         DoProcessMenu (menuItem);
  313.                 END;
  314.                 
  315.                 WHILE TickCount < (startTicks + 6) DO BEGIN
  316.                     (* Wait to make sure menu highlighting is visible. *)
  317.                 END;
  318.                 
  319.                 IF NOT gQuitting THEN BEGIN
  320.                     HiliteMenu (0);
  321.                 END;
  322.             END
  323.     END;
  324.  
  325.  
  326. {$S Main}
  327. (*******************************************************************************
  328. * Private: ResetMenuItems - Disable any disableable items and clear marks
  329. *
  330. * Disabling all the menu items is done bruteforcedly.  It could easily be done
  331. * by looping through each menu and disabling every item that comes up (disabling
  332. * a Font menu would be done this way), but I thought doing it using the brute-force
  333. * method was clearer.  Then again. . .
  334. *******************************************************************************)
  335.  
  336.     PROCEDURE ResetMenuItems;
  337.  
  338.         VAR
  339.             aMenu: MenuHandle; {Handle to each menu we’re disabling}
  340.  
  341.     BEGIN
  342.         (* Disable items in the File menu *)
  343.         aMenu := GetMenuHandle (mFile);
  344.         DisableItem (aMenu, iClose);
  345.         DisableItem (aMenu, iLaunchFore);
  346.         DisableItem (aMenu, iLaunchBack);
  347.         DisableItem (aMenu, iLaunchTo);
  348.         SetItemMark (aMenu, iJustLaunch, CHR (noMark));
  349.         SetItemMark (aMenu, iOpenLaunch, CHR (noMark));
  350.         SetItemMark (aMenu, iPrintLaunch, CHR (noMark));
  351.  
  352.         (* Disable items in the Process menu *)
  353.         aMenu := GetMenuHandle (mProcess);
  354.         DisableItem (aMenu, iBringFront);
  355.         DisableItem (aMenu, iShowProcessInfo);
  356.         DisableItem (aMenu, iTerminateProcess);
  357.     END;
  358.  
  359.  
  360. {$S Main}
  361. (*******************************************************************************
  362. * Public: FixMenus
  363. *
  364. * FixMenus first disables every available menu item.  Then the most basic menu
  365. * items are enabled.  The windowKind field of the front window is then checked.
  366. * If there is a window open, FixMenus calls a routine that’s responsible for
  367. * that kind of window to enable any menu items that are relevant to that kind of
  368. * window.
  369. *
  370. * After this is done, the menu bar might have to be redrawn to reflect the new
  371. * conditions.  So, FixMenus go through every menu to determine if the state of
  372. * the entire menu has changed.  The MenuGuide records are used to help determine
  373. * this.  If the state of any many has changed, then the menu bar is redrawn.
  374. *******************************************************************************)
  375.  
  376.     PROCEDURE FixMenus;
  377.  
  378.         VAR
  379.             currWindow: WindowPtr;  {Pointer to the front-most window}
  380.             currMenu:   MenuHandle; {Handle to menu being enabled}
  381.             oldEnables: LongInt;    {True if 1+ menu items enabled when FixMenus called}
  382.             newEnables: LongInt;    {True if 1+ menu items enabled after menus fixed}
  383.             mustRedraw: Boolean;    {TRUE if menu bar has to be redrawn}
  384.             numItems:   Integer;    {Number of items in a menu}
  385.             menuIndex:  Integer;    {Index into menu guide array}
  386.  
  387.     BEGIN
  388.         (* Start by disabling all menus *)
  389.         ResetMenuItems;
  390.  
  391.         (* Front-most window determines most menu enabling/disabling *)
  392.         currWindow := FrontWindow;
  393.  
  394.         (* Fix the marks for the launch mode items *)
  395.         currMenu := GetMenuHandle (mFile);
  396.         CASE GetLaunchMode OF
  397.             kJustLaunch:
  398.                 CheckItem (currMenu, iJustLaunch, TRUE);
  399.             kOpenLaunch:
  400.                 CheckItem (currMenu, iOpenLaunch, TRUE);
  401.             kPrintLaunch:
  402.                 CheckItem (currMenu, iPrintLaunch, TRUE)
  403.         END;
  404.  
  405.         (* Enable any window-specific menu items *)
  406.         IF currWindow <> NIL THEN
  407.             IF IsProcessListWindow (currWindow) THEN
  408.                 (* Process list window in front, set up menu items in it *)
  409.                 FixProcessListMenus (currWindow)
  410.             ELSE IF IsProcessInfoWindow (currWindow) THEN
  411.                 (* Process info window in front, set up menu items in it *)
  412.                 FixProcessInfoMenus (currWindow);
  413.  
  414.         (* Assume we don’t have to redraw the menu bar *)
  415.         mustRedraw := FALSE;
  416.  
  417.         (* Check through every menu to see if there are any enabled items in it *)
  418.         FOR menuIndex := mFirst TO mLast DO
  419.             BEGIN
  420.                 (* Grab the old and new enable flags excluding the flag for the entire menu *)
  421.                 oldEnables := BAnd (gMenuGuides [menuIndex].enables, $FFFFFFFE);
  422.                 newEnables := BAnd (gMenuGuides [menuIndex].theMenu^^.enableFlags,
  423.                         $FFFFFFFE);
  424.  
  425.                 (* Shift left so that we only see flags for existing items *)
  426.                 numItems := CountMItems (gMenuGuides [menuIndex].theMenu);
  427.                 oldEnables := BitShift (oldEnables, 31 - numItems);
  428.                 newEnables := BitShift (newEnables, 31 - numItems);
  429.  
  430.                 (* Determine if the menu bar must be redrawn *)
  431.                 IF (oldEnables <> 0) AND (newEnables = 0) THEN
  432.                     BEGIN
  433.                         (* Had some items enabled, now has no items enabled, redraw *)
  434.                         DisableItem (gMenuGuides [menuIndex].theMenu, 0);
  435.                         mustRedraw := TRUE
  436.                     END
  437.                 ELSE IF (oldEnables = 0) AND (newEnables <> 0) THEN
  438.                     BEGIN
  439.                         (* Had no items enabled, now has some items enabled, redraw *)
  440.                         EnableItem (gMenuGuides [menuIndex].theMenu, 0);
  441.                         mustRedraw := TRUE
  442.                     END;
  443.  
  444.                 (* Update our copy of the enable flags *)
  445.                 gMenuGuides [menuIndex].enables := gMenuGuides [menuIndex].
  446.                         theMenu^^.enableFlags
  447.             END;
  448.  
  449.         (* If at least one menu has changed state, must redraw the menu bar *)
  450.         IF mustRedraw THEN
  451.             InvalMenuBar
  452.     END;
  453.  
  454. END.
  455.